package ink.ykb.aoplog.config.log;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSONObject;

import ink.ykb.aoplog.config.CodeConstant;
import ink.ykb.aoplog.config.MessageUtil;
import ink.ykb.aoplog.config.ResponseMsg;
import ink.ykb.aoplog.config.ServiceException;
import lombok.extern.slf4j.Slf4j;

/**
 * redis阻塞锁	
 */
@Configuration
@Aspect
@Order(90)
@Slf4j
public class  AopLogConf {
	
		private final static String Token_Member_Id = "tokenMemberId";
		
		@Autowired
		private MessageUtil messageUtil;
		
		@Around("@annotation(aopLog)")
		public Object redisLockAop(ProceedingJoinPoint pjp,AopLog aopLog) throws Throwable{
			
			String name = aopLog.name();//接口名称 
			String ignoreParams = aopLog.ignoreParam();//忽略参数，以逗号分隔 
			boolean ignoreResult = aopLog.ignoreResult();//是否忽略返回数据 
			boolean ignoreResultData = aopLog.ignoreResultData();//是否忽略返回数据中的data
			String uri = "";//访问地址
			String uId = "";//当前用户
			ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
			if (requestAttributes != null && requestAttributes.getRequest() != null) {
				HttpServletRequest request = requestAttributes.getRequest();
				uri = request.getRequestURI();
				Object attribute = request.getAttribute(Token_Member_Id);
				uId = attribute!= null ? attribute.toString():"";
			}
			
			Map<String, Object> parameterNames = this.getParameterNames(pjp);//获取方法所有参数
			//移除忽略的参数
			if(ignoreParams != null && ignoreParams.trim() != null) {
				String[] ign = ignoreParams.split(",");
				for (int i = 0; i < ign.length; i++) {
					for (Iterator<Entry<String, Object>>  it = parameterNames.entrySet().iterator(); it.hasNext();){
						Entry<String, Object>  item = it.next();
						String key = item.getKey();
//						Object value = item.getValue();
						if(key.equals(ign[i]) 
//								|| (value instanceof HttpServletRequest) 
//								|| (value instanceof HttpServletResponse)
//								|| (value instanceof MultipartFile)
//								|| (value instanceof File)
								) {
							it.remove();
						}
					}
				}
			}
			
			String parameterStr = JSONObject.toJSONString(parameterNames);//当前用户
			Date date1 = new Date();
			
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss");
			Object result = null;
			String exMsg = null;
			try {
				result = pjp.proceed();
			} catch (Exception e) {
				exMsg = e.getMessage();
				throw e;
			}finally {
				Date date2 = new Date();
				String resultStr = null;
				if(!ignoreResult) {
					resultStr = JSONObject.toJSONString(result);
				}
				if(ignoreResultData) {
					if(result instanceof ResponseMsg) {
						ResponseMsg result2 = (ResponseMsg)result;
						if(result2 != null) {
							ResponseMsg result3 = new ResponseMsg();
							if(result2.getData() instanceof List) {
								result3.setData("List大小："+((List)result2.getData()).size());
							}
							
							result3.setCode(result2.getCode());
							result3.setMsg(result2.getMsg());
							result3.setTimestamp(result2.getTimestamp());
							resultStr = JSONObject.toJSONString(result3);
						}
					}
				}
				
				
				log.info("访问地址：{}，接口名称：{}，当前用户：{}，请求参数：{}，响应数据：{}，异常：{}，请求时间：{}，响应时间：{}，耗时：{}毫秒",
						uri,name,uId,parameterStr,resultStr,exMsg,simpleDateFormat.format(date1),simpleDateFormat.format(date2),date2.getTime()- date1.getTime());
			}
			
			return result;
		}
		
		
		/**
		 * 获取方法的参数
		 */
		private Map<String, Object> getParameterNames(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException{
			
			String[] names = null;//参数名
			Object[] args = pjp.getArgs();//参数值
			
			Signature signature = pjp.getSignature();  
	        MethodSignature methodSignature = (MethodSignature) signature;  
			
			String jv = System.getProperty("java.version");
			String[] jvs = jv.split("\\.");
			if(Integer.parseInt(jvs[0]+jvs[1]) >= 18) {//jdk8直接获取参数名
		        names = methodSignature.getParameterNames(); 
			}else {
				LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
		        Object target = pjp.getTarget();//代理类
		        Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
		        names = localVariableTableParameterNameDiscoverer.getParameterNames(currentMethod);
			}
			if(names == null) {
				throw new ServiceException(
						CodeConstant.LOG_000002,
						messageUtil.getMessage(CodeConstant.LOG_000002, pjp.getTarget().getClass().getName()+"$"+signature.getName()+"："));
			}
			
			Map<String, Object> map = new HashMap<>();
			if(names != null && names.length == args.length) {
				for (int i = 0; i < names.length; i++) {
					map.put(names[i], args[i]);
				}
			}
			return map;
		}
		
}
